/*
    This source file is part of GeNa project.
    Copyright © GeNa project 2008
    For the latest info, see http://code.google.com/p/genaproject/ or  http://lumpyproject.forums-rpg.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>. */

#ifdef WX_PRECOMP
#ifndef WX_PCH_H_INCLUDED
#include "wx_pch.h"
#endif
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__


#include <fstream>
#include <boost/archive/xml_oarchive.hpp>

#include "main_frame.h"
#include "property_manager.h"
#include "map_manager.h"
#include "windows_manager_serialization.h"
#include "action.h"

extern "C"
{
#include "icons/icon_big.xpm"
#include "icons/icon_medium.xpm"
#include "icons/icon_small.xpm"
#include "icons/icon_very_small.xpm"

#include "images/undo.xpm"
#include "images/redo.xpm"
}

//helper functions
enum wxbuildinfoformat {
    short_f, long_f };

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__WXMAC__)
        wxbuild << _T("-Mac");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}


BEGIN_EVENT_TABLE(MainFrame, wxFrame)
    EVT_CLOSE(MainFrame::OnClose)
    EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, MainFrame::OnPageChanged)
    EVT_AUINOTEBOOK_PAGE_CLOSE(wxID_ANY, MainFrame::OnPageClose)
    EVT_MENU(idMenuQuit, MainFrame::OnQuit)
    EVT_MENU(idMenuConfig, MainFrame::OnConfiguration)
    EVT_MENU(idMenuAbout, MainFrame::OnAbout)
    EVT_MENU(idMenuSave, MainFrame::OnSave)
    EVT_MENU(idMenuSaveAs, MainFrame::OnSave)
    EVT_MENU(idMenuNew, MainFrame::OnNew)
    EVT_MENU(idMenuOpen, MainFrame::OnOpen)

    EVT_MENU(idMenuRedo, MainFrame::OnRedo)
    EVT_MENU(idMenuUndo, MainFrame::OnUndo)

    EVT_MENU(idMenuRes1t64, MainFrame::OnResolution)
    EVT_MENU(idMenuRes2t64, MainFrame::OnResolution)
    EVT_MENU(idMenuRes4t64, MainFrame::OnResolution)
    EVT_MENU(idMenuRes8t64, MainFrame::OnResolution)
    EVT_MENU(idMenuRes16t64, MainFrame::OnResolution)
    EVT_MENU(idMenuRes32t64, MainFrame::OnResolution)
    EVT_MENU(idMenuRes64t4096, MainFrame::OnResolution)
    EVT_MENU(idMenuRes128t4096, MainFrame::OnResolution)
    EVT_MENU(idMenuRes512t4096, MainFrame::OnResolution)
    EVT_MENU(idMenuRes1024t4096, MainFrame::OnResolution)
    EVT_MENU(idMenuRes2048t4096, MainFrame::OnResolution)
    EVT_MENU(idMenuRes4096t262144, MainFrame::OnResolution)
    EVT_MENU(idMenuRes8192t262144, MainFrame::OnResolution)
    EVT_MENU(idMenuRes16384t262144, MainFrame::OnResolution)
END_EVENT_TABLE()

MainFrame::MainFrame(wxFrame *frame, const wxString& title)
    : wxFrame(frame, -1, title)
{
    conf = NULL;

    //Icon
    wxIconBundle iconBundle;
    iconBundle.AddIcon(wxIcon(icon_very_small_xpm));
    iconBundle.AddIcon(wxIcon(icon_small_xpm));
    iconBundle.AddIcon(wxIcon(icon_medium_xpm));
    iconBundle.AddIcon(wxIcon(icon_big_xpm));
    SetIcons(iconBundle);

    // create a menu bar
    wxMenuBar* mbar = new wxMenuBar();
    wxMenu* fileMenu = new wxMenu(_T(""));
    fileMenu->Append(idMenuNew, _("&Nouveau"), _("Crée une nouvelle carte vierge"));
    fileMenu->Append(idMenuOpen, _("&Ouvrir"), _("Ouvre une carte enregistrée"));
    fileMenu->Append(idMenuSave, _("&Enregistrer"), _("Enregistre la carte actuelle"));
    fileMenu->Append(idMenuSaveAs, _("&Enregistrer sous …"), _("Enregistre la carte actuelle sous un nom différent"));
    fileMenu->Append(idMenuQuit, _("&Quitter\tAlt-F4"), _("Fermer Triatek"));
    mbar->Append(fileMenu, _("&Fichier"));

    m_editMenu = new wxMenu(_T(""));
    m_editMenu->Append(idMenuUndo, _("&Annuler\tCtrl+Z"), _("Annuler l’action précédente"));
    m_editMenu->Append(idMenuRedo, _("&Rétablir\tCtrl+Shift+Z"), _("Rétablir l’action annuler"));
    m_editMenu->Append(idMenuConfig, _("&Préférences\tF2"), _("Préférences de l’éditeur"));
    mbar->Append(m_editMenu, _("&Édition"));

    //Resolution menu
    wxMenu* resMenu = new wxMenu(_T(""));
    resMenu->Append(idMenuRes1t64, _("Grille &1−64 (1,56 cm)"));
    resMenu->Append(idMenuRes2t64, _("Grille 2−64"));
    resMenu->Append(idMenuRes4t64, _("Grille 4−64"));
    resMenu->Append(idMenuRes8t64, _("Grille &8−64 (12,5 cm)"));
    resMenu->Append(idMenuRes16t64, _("Grille 16−64"));
    resMenu->Append(idMenuRes32t64, _("Grille 32−64"));
    resMenu->Append(idMenuRes64t4096, _("Grille &64−4096 (1 m)"));
    resMenu->Append(idMenuRes128t4096, _("Grille 128−4096"));
    resMenu->Append(idMenuRes512t4096, _("Grille 512−4096"));
    resMenu->Append(idMenuRes1024t4096, _("Grille &1024−4096 (16 m)"));
    resMenu->Append(idMenuRes2048t4096, _("Grille 2048−4096"));
    resMenu->Append(idMenuRes4096t262144, _("Grille 4096−262144"));
    resMenu->Append(idMenuRes8192t262144, _("Grille &8192−262144"));
    resMenu->Append(idMenuRes16384t262144, _("Grille 16384−262144 (256 m)"));
    mbar->Append(resMenu, _("&Résolution"));

    wxMenu* helpMenu = new wxMenu(_T(""));
    helpMenu->Append(idMenuAbout, _("&À propos\tF1"), _("À propos de l’éditeur Triatek !"));
    mbar->Append(helpMenu, _("&Aide"));

    SetMenuBar(mbar);

    // create a status bar with some information about the used wxWidgets version
    CreateStatusBar(3);
    //0 - current position
    SetStatusText(_("Bienvenue dans Triatek !"),1); //1 - information
    SetStatusText(wxbuildinfo(short_f), 2); //WxWidget

    //Create window
    wxSize size = GetClientSize();
    m_auiNotebook = new wxAuiNotebook(this, wxID_ANY,wxDefaultPosition, wxDefaultSize, wxAUI_NB_DEFAULT_STYLE);

    m_logWnd = new wxTextCtrl(this, wxID_ANY,_(""),wxDefaultPosition, wxDefaultSize,wxTE_READONLY|wxTE_MULTILINE);
    m_logWnd->SetMinSize(wxSize(200,200));

    m_log = new wxLogChain(new wxLogTextCtrl(m_logWnd));

    m_standard = new wxToolBar(this, wxID_ANY);
    m_standard->SetToolBitmapSize(wxSize(22,22));
    m_standard->SetMargins(0,0);
    m_standard->AddTool(idMenuUndo, _("Annuler"), wxBitmap(undo_xpm), _("Annuler l’action précédente."));
    m_standard->AddTool(idMenuRedo, _("Rétablir"), wxBitmap(redo_xpm), _("Rétablir l’action annulée."));

    m_standard->EnableTool(idMenuUndo, false);
    m_editMenu->Enable(idMenuUndo, false);
    m_standard->EnableTool(idMenuRedo, false);
    m_editMenu->Enable(idMenuRedo, false);

    m_standard->Realize();

    m_auiMgr = new wxAuiManager(this);
    m_auiMgr->AddPane(m_auiNotebook, wxAuiPaneInfo().Centre().CaptionVisible(false));
    m_auiMgr->AddPane(m_logWnd,wxAuiPaneInfo().Bottom().PinButton().Caption(_("Log")));
    m_auiMgr->AddPane(m_standard, wxAuiPaneInfo().ToolbarPane().Top());
    m_auiMgr->Update();
}


MainFrame::~MainFrame()
{
}


void MainFrame::OnClose(wxCloseEvent &event)
{
    std::ofstream ofs("config.xml");

    try
    {
        boost::archive::xml_oarchive oa(ofs);
        oa << make_nvp("mainFrame",*this);
        oa << make_nvp("properties",propMgrInstance);
    }
    catch(...)
    {
        ofs.close();
    }
    ofs.close();

    std::ofstream ofs2("layout.xml");

    try
    {
        boost::archive::xml_oarchive oa2(ofs2);
        oa2 << make_nvp("sys",*mapManagerInstance.current->mgr);
    }
    catch(...)
    {
        ofs2.close();
    }
    ofs2.close();


    for( unsigned int i = 0; i < m_auiNotebook->GetPageCount(); i++)
    {
        if(!(dynamic_cast<MapBasePane*>(m_auiNotebook->GetPage(i)))->map->printMessageAndEventuallyDestroy(event.CanVeto()))
        {
            event.Veto();
            return;
        }
    }

    appInstance->mTimer.Stop();
    Destroy();
    GLWindow::deinitGLWindow();
}

void MainFrame::OnQuit(wxCommandEvent &event)
{
}

void MainFrame::OnAbout(wxCommandEvent &event)
{
    wxString msg = _("L’Éditeur Triatek permet de créer des niveaux du jeu GenaTek.\n\n\n\n\nInformations relatives à la compilation :\n") + wxbuildinfo(long_f);
    wxMessageBox(msg, _("À propos"));
}

void MainFrame::OnConfiguration(wxCommandEvent &event)
{
    if( !conf)
        conf = new ConfWindow(this);
    conf->Show();
    conf->SetFocus();
}

void MainFrame::OnResolution(wxCommandEvent &event)
{
    int pw = event.GetId();
    int res = 1 << (pw-1);

    int res2;
    if( res < 64)
        res2 = 64;
    else if( res < 4096)
        res2 = 4096;
    else
        res2 = 262144;

    propMgrInstance.setPropertyValue(std::string("EditorWindow.res"),res);
    propMgrInstance.setPropertyValue(std::string("EditorWindow.res2"),res2);
}

void MainFrame::OnSave(wxCommandEvent &event)
{
    if( event.GetId() == idMenuSave)
        mapManagerInstance.save(mapManagerInstance.current);
    else
        mapManagerInstance.saveAs(mapManagerInstance.current);
}

void MainFrame::OnNew(wxCommandEvent& event)
{
    wxLogMessage(_("Chargement d’une carte vierge"));
    mapManagerInstance.setCurrent(mapManagerInstance.newMap());
}

void MainFrame::OnOpen(wxCommandEvent& event)
{
    mapManagerInstance.open();
}

void MainFrame::OnUndo(wxCommandEvent &event)
{
    actionManagerInstance.undo(1);
}

void MainFrame::OnRedo(wxCommandEvent &event)
{
    actionManagerInstance.redo(1);
}

void MainFrame::OnPageChanged(wxAuiNotebookEvent& event)
{
    mapManagerInstance.setCurrent((dynamic_cast<MapBasePane*>(m_auiNotebook->GetPage(event.GetSelection())))->map);
}

void MainFrame::OnPageClose(wxAuiNotebookEvent& event)
{
    if(!(dynamic_cast<MapBasePane*>(m_auiNotebook->GetPage(event.GetSelection())))->map->printMessageAndEventuallyDestroy(true))
        event.Veto();
    else
    {
        if( m_auiNotebook->GetPageCount() == 1)
            appInstance->m_frame->Close();
    }
}
